package beanstao.util.store.dal;

import java.util.HashMap;
import java.util.List;

import org.dom4j.Element;
import org.dom4j.Node;

import beanstao.util.Dates;
import beanstao.util.id.Id;
import beanstao.util.store.dal.interfaces.IDomainXmlTreeCreate;
import beanstao.util.store.dal.interfaces.IDomainXmlTreeDelete;
import beanstao.util.store.dal.interfaces.IDomainXmlTreeRemove;
import beanstao.util.store.dal.interfaces.IDomainXmlTreeSelect;
import beanstao.util.store.dal.interfaces.IDomainXmlTreeUpdate;
import beanstao.util.store.database.Fields;
import beanstao.util.store.domainobject.DomainList;
import beanstao.util.store.domainobject.XmlDomain;
import beanstao.util.store.domainobject.fields.PublicField;
import beanstao.util.xml.XDocument;


/**
 * 这是一个针对DomainObject的Dal的“XML格式(树状)”的抽象类(复杂格式，树状)，所有的持久化方法均已经基本实现。<BR>
 * 
 * @author beanstao@google.com 
 * @param <T>
 */
public abstract class XmlTreeDal<T extends XmlDomain> extends XmlDal<T> implements IDomainXmlTreeCreate<XmlDomain>, IDomainXmlTreeDelete<XmlDomain>, IDomainXmlTreeRemove, IDomainXmlTreeSelect<XmlDomain>, IDomainXmlTreeUpdate<XmlDomain>
{

	public XmlTreeDal(final XDocument docment, final Fields fields)
	{
		super(docment, fields);
	}

	public boolean isTree()
	{
		return true;
	}

	@Override
	public boolean create(final Id parentId, final XmlDomain domain)
	{
		try
		{
			Element parentElement = (Element) _CoreElement.selectSingleNode(String.format("//%s[@id='%s']", _Fields.getName(), parentId));
			if (null == parentElement)
				return false;
			Element ele = domain.toXmlElement();
			XDocument.setAttribute(ele, PublicField.CREATED_TIME, Dates.nowToGeneralLongString());
			parentElement.add(ele);
			_OwnerDocument.save();
			return true;
		}
		catch (Exception e)
		{
			return false;
		}
	}

	@Override
	public int create(final Id parentId, final DomainList<XmlDomain> domainList)
	{
		for (XmlDomain xmlDomainObject : domainList)
			this.create(parentId, xmlDomainObject);
		return domainList.size();
	}

	@Override
	public int deleteChilds(final Id modifiorId, final Id parentId)
	{
		Element parentElement = (Element) _CoreElement.selectSingleNode(String.format("//%s[@id='%s']", _Fields.getName(), parentId));
		int size = this.deleteChildElement(modifiorId, parentElement);
		_OwnerDocument.save();
		return size;
	}

	@Override
	public int removeChilds(final Id modifiorId, final Id parentId)
	{
		Element parentElement = (Element) _CoreElement.selectSingleNode(String.format("//%s[@id='%s']", _Fields.getName(), parentId));
		int i = parentElement.selectNodes(String.format("descendant::%s[@id]", _Fields.getName())).size();
		while (parentElement.elements().size() > 0)
			parentElement.remove(parentElement.elements().get(0));
		this.logInfo(String.format("用户%s将%s中ID=%s的节点的子节点全部彻底删除。", modifiorId, _Fields.getName(), parentId));
		_OwnerDocument.save();
		return i;
	}

	@Override
	public DomainList<XmlDomain> selectChilds(final Id parentId)
	{
		DomainList<XmlDomain> list = new DomainList<XmlDomain>();
		Node node = null;
		if (null == parentId)
			node = _CoreElement;
		else
			node = _CoreElement.selectSingleNode(String.format("//%s[@id='%s']", _Fields.getName(), parentId));
		String xpath = String.format("descendant::%s[@id]", _Fields.getName());// %s[@id]
		List<?> workNodeList = node.selectNodes(xpath);
		for (Object object : workNodeList)
		{
			HashMap<String, String> map = XDocument.toMapByAttributes((Node) object);
			XmlDomain domain = this.newBlankDomain();
			domain.putAll(map);
			if (domain.getIsDeleted())
				continue;
			list.add(domain);
		}
		this.logDebug("XML Select All Childs Size: " + workNodeList.size());
		return list;
	}

	@Override
	public DomainList<XmlDomain> selectElements(final Id parentId)
	{
		DomainList<XmlDomain> list = new DomainList<XmlDomain>();
		Node node = _CoreElement.selectSingleNode(String.format("//%s[@id='%s']", _Fields.getName(), parentId));
		if ((null != node) && (node instanceof Element))
		{
			Element work = (Element) node;
			for (Element child : work.elements())
			{
				HashMap<String, String> map = XDocument.toMapByAttributes(child);
				XmlDomain domain = this.newBlankDomain();
				domain.putAll(map);
				list.add(domain);
			}
		}
		return list;
	}

	@Override
	public boolean existElement(Id parentId, Id elementId)
	{
		return this.existElement(parentId, "id", elementId.toString());
	}

	@Override
	public boolean existElement(Id parentId, String attrubuteName, String attrubuteValue)
	{
		Node parent = _CoreElement.selectSingleNode(String.format("//%s[@id='%s']", _Fields.getName(), parentId));
		if (null == parent)// 当父节点未找到时
			return false;
		String xpath = String.format("child::%s[@%s='%s']", _Fields.getName(), attrubuteName, attrubuteValue);
		Node node = parent.selectSingleNode(xpath);
		if ((null == node) || !(node instanceof Element))
			return false;
		else
			return true;
	}

	@Override
	public DomainList<XmlDomain> childAttributes(final Id id, final String attrName)
	{
		return this.attributesByXpath(true, id, attrName);
	}

	@Override
	public DomainList<XmlDomain> elementAttributes(final Id id, final String attrName)
	{
		return this.attributesByXpath(false, id, attrName);
	}

	/**
	 * 查找指定的属性值
	 * 
	 * @param id
	 * @param attrName
	 * @return
	 */
	private DomainList<XmlDomain> attributesByXpath(final Boolean isChild, final Id id, final String attrName)
	{
		DomainList<XmlDomain> list = new DomainList<XmlDomain>();
		Node node = _CoreElement.selectSingleNode(String.format("//%s[@id='%s']", _Fields.getName(), id));
		if ((null != node) && (node instanceof Element))
		{
			String xpath = "";
			if (isChild)
				xpath = String.format("child::%s[@id]/@%s", _Fields.getName(), attrName);
			else
				xpath = String.format("descendant::%s[@id]/@%s", _Fields.getName(), attrName);
			List<?> nodes = node.selectNodes(xpath);
			for (Object childNode : nodes)
			{
				XmlDomain domain = this.newBlankDomain();
				domain.put(attrName, ((Node) childNode).getText().trim());
				list.add(domain);
			}
		}
		return list;
	}

	public XmlDomain selectParent(final Id ownerId)// parent
	{
		XmlDomain domain = this.newBlankDomain();
		Node node = _CoreElement.selectSingleNode(String.format("//%s[@id='%s']", _Fields.getName(), ownerId));
		if (null == node)
			return domain;
		Node parentNode = node.selectSingleNode(String.format("parent::%s[@id]", _Fields.getName()));
		if ((null != parentNode) && (parentNode instanceof Element))
		{
			HashMap<String, String> map = XDocument.toMapByAttributes(parentNode);
			domain.putAll(map);
		}
		return domain;
	}

	@Override
	public DomainList<XmlDomain> selectAncestor(final Id ownerId)// stationid
	{
		DomainList<XmlDomain> dl = new DomainList<XmlDomain>();
		Node node = _CoreElement.selectSingleNode(String.format("//%s[@id='%s']", _Fields.getName(), ownerId));
		if (null == node)
			return dl;
		String xpath = String.format("ancestor::%s[@id]", _Fields.getName());
		List<?> list = node.selectNodes(xpath);
		if ((null != node) && (node instanceof Element) && (null != list) && (list.size() > 0))
			for (Object child : list)
			{
				HashMap<String, String> map = XDocument.toMapByAttributes((Element) child);
				XmlDomain domain = this.newBlankDomain();
				domain.putAll(map);
				dl.add(domain);
			}
		return dl;
	}

	public Element xml(Id id)
	{
		String xpath = String.format("//%s[@id='%s']", _Fields.getName(), id);
		Node node = _CoreElement.selectSingleNode(xpath);
		if (node instanceof Element)
			return (Element) node;
		return null;
	}
}
